package com.yilin.tms.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yilin.commons.util.ArrayUtil;
import com.yilin.commons.util.JsonUtil;
import com.yilin.tms.core.application.ReturnData;
import com.yilin.tms.core.entity.system.system.Menu;
import com.yilin.tms.core.entity.system.system.MenuOperate;
import com.yilin.tms.core.entity.user.UserType;
import com.yilin.tms.core.entity.user.grant.GrantMenu;
import com.yilin.tms.core.entity.user.grant.GrantMenuOperate;
import com.yilin.tms.core.entity.user.grant.GrantRoleMenu;
import com.yilin.tms.core.entity.user.grant.GrantRoleMenuOperate;
import com.yilin.tms.core.entity.user.organize.MemberType;
import com.yilin.tms.core.entity.user.organize.Organize;
import com.yilin.tms.core.entity.user.organize.UserRole;
import com.yilin.tms.core.remote.ISystemRemote;
import com.yilin.tms.user.service.*;
import com.yilin.tms.user.mapper.GrantMenuMapper;
import com.yilin.tms.user.mapper.GrantMenuOperateMapper;
import com.yilin.tms.user.service.IGrantMenuService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.function.Consumer;

@Service
public class GrantMenuService extends ServiceImpl<GrantMenuMapper, GrantMenu> implements IGrantMenuService {

    @Resource
    private GrantMenuMapper grantMenuMapper;
    @Resource
    private GrantMenuOperateMapper grantMenuOperateMapper;

    @Resource
    private IMemberTypeService memberTypeService;
    @Resource
    private ISystemRemote systemRemote;
    @Resource
    private IOrganizeService organizeService;
    @Resource
    private IRoleService roleService;
    @Resource
    private IGrantRoleMenuService grantRoleMenuService;

    private List<Menu> getMenuListByCodes(List<String> grantCodeList) {
        ReturnData<List<Menu>> returnData = systemRemote.getMenuListByCodes(String.join(",",grantCodeList));
        if (returnData == null) return new ArrayList<>();
        return returnData.getData();
    }

    private Map<String,ArrayList<MenuOperate>> getMenuOperateListMapByCodes(Map<String,String[]> menuCodeOperateCodes) {
        ReturnData<Map<String, ArrayList<MenuOperate>>> returnData = systemRemote.getMenuOperateListMapByCodes(JsonUtil.objectToJson(menuCodeOperateCodes));
        if (returnData == null) return new HashMap<>();
        return returnData.getData();
    }

    /**
     * 公共调取
     * 自动封装菜单权限及其操作权限
     * 获取对应会员的菜单及其操作信息
     * */
    @Override
    public List<Menu> getGrantMenuOperateList(UserType userType, String memberTypeId){
        List<Menu> menuList;
        if (userType == UserType.adminUser) menuList = getAllMenuList();
        else menuList = getGrantMenuList(memberTypeId);
        //### 获取对应菜单CODE集合
        List<String> menuCodeList = ArrayUtil.fieldAdd(menuList, Menu::getCode);
        //### 获取对应菜单CODE---ADMIN 所有按钮权限
        Map<String, ArrayList<MenuOperate>> allMenuOperateListMap = getMenuOperateListByMenuCodes(menuCodeList.toArray(new String[]{}));
        //### 获取对应菜单CODE---当前按钮权限
        Map<String, ArrayList<MenuOperate>> grantMenuOperateListMap = getGrantMenuOperateListMap(memberTypeId, menuCodeList.toArray(new String[]{}));
        //### 封装列表
        for (Menu menu : menuList) {
            List<MenuOperate> operateList;
            if (userType == UserType.adminUser) operateList = allMenuOperateListMap.get(menu.getCode());
            else operateList = grantMenuOperateListMap.get(menu.getCode());
            menu.setMenuOperateList(operateList);
        }
        return menuList;
    }

    /**
     * 检查权限
     * */
    @Override
    public Map<String, String[]> checkAuthorityMap(UserType userType, String memberTypeId, Map<String, String[]> authorityMap){
        /// 获取自己在上级平台拥有的权限
        List<Menu> menuList = getGrantMenuOperateList(userType, memberTypeId);
        /// 开始检查权限--菜单
        //  如果上级没有权限，移除他
        List<String> menuCodeList = ArrayUtil.fieldAdd(menuList, Menu::getCode);
        List<String> removeKeyList = new ArrayList<>();
        for (String menuCode : authorityMap.keySet()) {
            if (!menuCodeList.contains(menuCode)) removeKeyList.add(menuCode);
        }
        removeKeyList.forEach(authorityMap::remove);
        /// 开始检查权限--按钮
        for (String menuCode : authorityMap.keySet()) {
            Menu menu = ArrayUtil.getBy(menuList, obj -> menuCode.equals(obj.getCode()));
            if ( menu == null ) continue;
            List<String> operateCodeList = ArrayUtil.initList(authorityMap.get(menuCode));
            List<MenuOperate> operateList = menu.getMenuOperateList();
            //如果上级没有权限，移除他
            List<String> menuOperateCodeList = ArrayUtil.fieldAdd(operateList, MenuOperate::getCode);
            List<String> removeOptKeyList = new ArrayList<>();
            for (String operateCode : operateCodeList) {
                if (!menuOperateCodeList.contains(operateCode))  removeOptKeyList.add(operateCode);
            }
            removeOptKeyList.forEach(operateCodeList::remove);
            authorityMap.put(menuCode,operateCodeList.toArray(new String[]{}));
        }
        return authorityMap;
    }


    /**
     * 获取平台所有权限
     */
    @Override
    public List<Menu> getAllMenuList() {
        ReturnData<List<Menu>> returnData = systemRemote.getAllMenuList();
        if (returnData == null) return new ArrayList<>();
        return returnData.getData();
    }

    /**
     * 获取会员授权列表
     */
    @Override
    public List<Menu> getGrantMenuList(String memberTypeId) {
        List<String> grantApiCodeList = getGrantMenuCodeList(memberTypeId);
        return getMenuListByCodes(grantApiCodeList);
    }


    /**
     * 获取菜单所有操作权限推荐
     */
    @Override
    public Map<String, ArrayList<MenuOperate>> getMenuOperateListByMenuCodes(String[] menuCodes) {
        ReturnData<Map<String, ArrayList<MenuOperate>>> returnData = systemRemote.getMenuOperateListByMenuCodes(String.join(",", menuCodes));
        if (returnData == null) return new HashMap<>();
        return  returnData.getData();
    }

    /**
     * 获取菜单已授权操作权限推荐
     */
    @Override
    public Map<String,ArrayList<MenuOperate>> getGrantMenuOperateListMap(String memberTypeId, String[] menuCodes) {
        Map<String,String[]> menuCodeOperateCodes = new HashMap<>();
        for (String menuCode : menuCodes) {
            List<String> grantMenuOperateCodeList = getGrantMenuOperateCodeList(memberTypeId, menuCode);
            menuCodeOperateCodes.put(menuCode,grantMenuOperateCodeList.toArray(new String[]{}));
        }
        return getMenuOperateListMapByCodes(menuCodeOperateCodes);
    }



    //获取会员授权CODE列表
    @Override
    public List<String> getGrantMenuCodeList(String memberTypeId) {
        return grantMenuMapper.getGrantMenuCodeList(memberTypeId);
    }

    //获取会员授权操作CODE列表
    @Override
    public List<String> getGrantMenuOperateCodeList(String memberTypeId, String menuCode) {
        return grantMenuOperateMapper.getGrantMenuOperateCodeList(memberTypeId, menuCode);
    }



    /**
     * 更新权限
     */
    @Override
    public void updateGrantMenuList(String memberTypeId, Map<String, String[]> authorityMap) {
        MemberType memberType = memberTypeService.getById(memberTypeId);
        List<String> grantCodeList = getGrantMenuCodeList(memberTypeId);
        // ### 添加新增的权限
        for (String menuCode : authorityMap.keySet()) {
            if (!grantCodeList.contains(menuCode)) {
                GrantMenu menu = new GrantMenu();
                menu.setMemberTypeId(memberTypeId);
                menu.setMenuCode(menuCode);
                grantMenuMapper.insert(menu);
            }
            //操作权限
            List<String> grantOperateCodeList = getGrantMenuOperateCodeList(memberTypeId, menuCode);
            for (String operateCode : authorityMap.get(menuCode)) {
                if (!grantOperateCodeList.contains(operateCode)) {
                    GrantMenuOperate menuOperate = new GrantMenuOperate();
                    menuOperate.setMemberTypeId(memberTypeId);
                    menuOperate.setMenuCode(menuCode);
                    menuOperate.setMenuOperateCode(operateCode);
                    grantMenuOperateMapper.insert(menuOperate);
                }
            }
        }
        // ### 所有该会员下的组织【管理员】默认获得新增的权限
        // ### 去除默认新增权限，组织会员权限变动时，需要手动更新所有角色权限。
        // 去除原因，用户过多时，因为大量的角色权限需要更新，导致系统卡顿
        // 也就是：下级平台/货主/司机 登录后台时，都要打开角色管理，刷新角色权限
//        List<Organize> organizeList = organizeService.getOrganizeListByMemberTypeId(memberTypeId);
//        organizeList.forEach(organize -> {
//            UserRole role = roleService.getManagerRoleByOrganizeId(organize.getId());
//            List<String> grantRoleMenuCodeList = grantRoleMenuService.getGrantRoleMenuCodeList(role.getId());
//            for (String menuCode : authorityMap.keySet()) {
//                if (!grantRoleMenuCodeList.contains(menuCode)) {
//                    GrantRoleMenu api = new GrantRoleMenu();
//                    api.setRoleId(role.getId());
//                    api.setMenuCode(menuCode);
//                    grantRoleMenuService.save(api);
//                }
//                //操作权限
//                List<String> grantRoleMenuOperateCodeList = grantRoleMenuService.getGrantRoleMenuOperateCodeList(role.getId(), menuCode);
//                for (String operateCode : authorityMap.get(menuCode)) {
//                    if (!grantRoleMenuOperateCodeList.contains(operateCode)) {
//                        GrantRoleMenuOperate roleMenuOperate = new GrantRoleMenuOperate();
//                        roleMenuOperate.setRoleId(role.getId());
//                        roleMenuOperate.setMenuCode(menuCode);
//                        roleMenuOperate.setMenuOperateCode(operateCode);
//                        grantRoleMenuService.saveRoleMenuOperate(roleMenuOperate);
//                    }
//                }
//            }
//        });
        // ### 移除失效的权限
        removeOrganizeGrant(grantCodeList, authorityMap, memberTypeId);
        // ### 移除(收回)会员指向组织下所有下级组织失效的权限
        removeChildGrantMenu(memberType.getOrganizeId(), authorityMap);
    }

    /// ### 收回所有下级平台的权限
    private void removeChildGrantMenu(String surOrganizeId, Map<String, String[]> authorityMap) {
        List<Organize> childOrganizeList = organizeService.getOrganizeListBySuperOrganizeId(surOrganizeId);
        childOrganizeList.forEach(childOrganize -> {
            if (childOrganize.getMemberTypeId() == null) return;
            // ### 移除组织失效的权限
            List<String> grantCodeList = getGrantMenuCodeList(childOrganize.getMemberTypeId());
            removeOrganizeGrant(grantCodeList, authorityMap, childOrganize.getMemberTypeId());
            // ### 移除组织下所有角色失效的权限
            List<UserRole> roleList = roleService.getUserRoleListByOrganizeId(childOrganize.getId());
            removeRoleGrant(roleList, authorityMap);
            // ### 递归遍历，移除所有下级平台组织的权限
            removeChildGrantMenu(childOrganize.getId(), authorityMap);
        });
    }

    /// ### 批量移除会员权限  123,23
    private void removeOrganizeGrant(List<String> grantCodeList, Map<String, String[]> authorityMap, String memberTypeId) {
        for (String menuCode : grantCodeList) {
            if (!authorityMap.containsKey(menuCode)) {
                removeGrantMenu(memberTypeId, menuCode);
            }
            List<String> grantOperateCodeList = getGrantMenuOperateCodeList(memberTypeId, menuCode);
            for (String grantOperateCode : grantOperateCodeList) {
                if (!authorityMap.containsKey(menuCode) || !Arrays.asList(authorityMap.get(menuCode)).contains(grantOperateCode)) {
                    removeGrantMenuOperate(memberTypeId, menuCode, grantOperateCode);
                }
            }
        }
    }

    /// ### 批量移除角色权限
    private void removeRoleGrant(List<UserRole> roleList, Map<String, String[]> authorityMap) {
        for (UserRole userRole : roleList) {
            List<String> menuCodeList = grantRoleMenuService.getGrantRoleMenuCodeList(userRole.getId());
            for (String roleMenuCode : menuCodeList) {
                if (!authorityMap.containsKey(roleMenuCode)) {
                    grantRoleMenuService.removeGrantRoleMenu(userRole.getId(), roleMenuCode);
                }
                List<String> grantOperateCodeList = grantRoleMenuService.getGrantRoleMenuOperateCodeList(userRole.getId(), roleMenuCode);
                for (String grantOperateCode : grantOperateCodeList) {
                    if (!authorityMap.containsKey(roleMenuCode) || !Arrays.asList(authorityMap.get(roleMenuCode)).contains(grantOperateCode)) {
                        grantRoleMenuService.removeGrantRoleMenuOperate(userRole.getId(), roleMenuCode, grantOperateCode);
                    }
                }
            }
        }
    }

    @Override
    public void removeGrantMenu(String memberTypeId, String menuCode) {
        QueryWrapper<GrantMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("member_type_id", memberTypeId);
        wrapper.eq("menu_code", menuCode);
        grantMenuMapper.delete(wrapper);
    }

    @Override
    public void removeGrantMenuOperate(String memberTypeId, String menuCode, String menuOperateCode) {
        QueryWrapper<GrantMenuOperate> wrapper = new QueryWrapper<>();
        wrapper.eq("member_type_id", memberTypeId);
        wrapper.eq("menu_code", menuCode);
        wrapper.eq("menu_operate_code", menuOperateCode);
        grantMenuOperateMapper.delete(wrapper);
    }
}
